﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Recipes.ModelWithLookup
{
    /// <summary>
    /// This scenario performs basic CRUD operations on a model containing a foreign key represented by an integer.
    /// </summary>
    /// <typeparam name="TModel">An Employee model or entity</typeparam>
    [TestCategory("ModelWithLookupSimple")]
    public abstract class ModelWithLookupSimpleTests<TModel> : TestBase
    where TModel : class, IEmployeeSimple, new()
    {
        /// <summary>
        /// Create and delete a row.
        /// </summary>
        [TestMethod]
        public void CreateAndDelete()
        {
            var repository = GetScenario();

            var employeeClassification = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification);

            var newRecord = new TModel
            {
                FirstName = "Test",
                MiddleName = "A",
                LastName = "Person " + DateTime.Now.Ticks,
                EmployeeClassificationKey = employeeClassification!.EmployeeClassificationKey
            };
            var newKey = repository.Create(newRecord);
            Assert.IsTrue(newKey >= 1000, "keys under 1000 were not generated by the database");

            var echo = repository.GetByKey(newKey);
            Assert.IsNotNull(echo);
            Assert.AreEqual(newKey, echo!.EmployeeKey);
            Assert.AreEqual(newRecord.FirstName, echo.FirstName);
            Assert.AreEqual(newRecord.LastName, echo.LastName);
            Assert.AreEqual(newRecord.EmployeeClassificationKey, echo.EmployeeClassificationKey);

            repository.Delete(echo);

            Assert.IsNull(repository.GetByKey(newKey), "Employee record should have been deleted.");

            var employeeClassification2 = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification2, "Delete method should not delete the EmployeeClassification record");
        }

        /// <summary>
        /// Create and delete a row.
        /// </summary>
        [TestMethod]
        public void CreateAndDeleteByKey()
        {
            var repository = GetScenario();

            var employeeClassification = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification);

            var newRecord = new TModel
            {
                FirstName = "Test",
                MiddleName = "A",
                LastName = "Person " + DateTime.Now.Ticks,
                EmployeeClassificationKey = employeeClassification!.EmployeeClassificationKey
            };
            var newKey = repository.Create(newRecord);
            Assert.IsTrue(newKey >= 1000, "keys under 1000 were not generated by the database");

            var echo = repository.GetByKey(newKey);
            Assert.IsNotNull(echo);
            Assert.AreEqual(newKey, echo!.EmployeeKey);
            Assert.AreEqual(newRecord.FirstName, echo.FirstName);
            Assert.AreEqual(newRecord.LastName, echo.LastName);
            Assert.AreEqual(newRecord.EmployeeClassificationKey, echo.EmployeeClassificationKey);

            repository.DeleteByKey(newKey);

            Assert.IsNull(repository.GetByKey(newKey), "Employee record should have been deleted.");

            var employeeClassification2 = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification2, "Delete method should not delete the EmployeeClassification record");
        }

        /// <summary>
        /// Create and read back a row.
        /// </summary>
        [TestMethod]
        public void CreateAndReadBack()
        {
            var repository = GetScenario();

            var employeeClassification = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification);

            var newRecord = new TModel
            {
                FirstName = "Test",
                MiddleName = "A",
                LastName = "Person " + DateTime.Now.Ticks,
                EmployeeClassificationKey = employeeClassification!.EmployeeClassificationKey
            };
            var newKey = repository.Create(newRecord);
            Assert.IsTrue(newKey >= 1000, "keys under 1000 were not generated by the database");

            var echo = repository.GetByKey(newKey);
            Assert.IsNotNull(echo);
            Assert.AreEqual(newKey, echo!.EmployeeKey);
            Assert.AreEqual(newRecord.FirstName, echo.FirstName);
            Assert.AreEqual(newRecord.LastName, echo.LastName);
            Assert.AreEqual(newRecord.EmployeeClassificationKey, echo.EmployeeClassificationKey);
        }

        /// <summary>
        /// Create and update a row.
        /// </summary>
        [TestMethod]
        public void CreateAndUpdate()
        {
            var repository = GetScenario();

            var employeeClassification = repository.GetClassification(2);
            Assert.IsNotNull(employeeClassification);

            var newRecord = new TModel
            {
                FirstName = "Test",
                MiddleName = "A",
                LastName = "Person " + DateTime.Now.Ticks,
                EmployeeClassificationKey = employeeClassification!.EmployeeClassificationKey
            };
            var newKey = repository.Create(newRecord);
            Assert.IsTrue(newKey >= 1000, "keys under 1000 were not generated by the database");

            var echo = repository.GetByKey(newKey);
            Assert.IsNotNull(echo);
            Assert.AreEqual(newKey, echo!.EmployeeKey);
            Assert.AreEqual(newRecord.FirstName, echo.FirstName);
            Assert.AreEqual(newRecord.LastName, echo.LastName);
            Assert.AreEqual(newRecord.EmployeeClassificationKey, echo.EmployeeClassificationKey);

            var updatedEmployeeClassification = repository.GetClassification(4);
            Assert.IsNotNull(updatedEmployeeClassification);

            echo.EmployeeClassificationKey = updatedEmployeeClassification!.EmployeeClassificationKey;
            repository.Update(echo);

            var echo2 = repository.GetByKey(newKey);
            Assert.IsNotNull(echo2);
            Assert.AreEqual(newKey, echo2!.EmployeeKey);
            Assert.AreEqual(echo.FirstName, echo2.FirstName);
            Assert.AreEqual(echo.LastName, echo2.LastName);
            Assert.AreEqual(updatedEmployeeClassification.EmployeeClassificationKey, echo2.EmployeeClassificationKey);
        }

        protected abstract IModelWithLookupSimpleScenario<TModel> GetScenario();
    }
}
